/*
    jME Task Framework, for executing tasks in a Java/OpenGL enviroment
    Copyright (C) 2005-2006,  Tijl Houtbeckers
    
    **** LICENSE: ****

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation,
	version 2.1.
	
	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.
	
	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

	**** CONTACT: ****

    I can be reached through the jmonkeyengine.com forums (user "llama"), 
    or the jmonkeyengine.com contact page:
    jmonkeyengine.com/index.php?option=com_contact&task=view&contact_id=5           

*/

/**
 * @author Tijl Houtbeckers
 */

package org.llama.jmex.task;

public abstract class AbstractThreadTaskRunner extends TaskRunner {
	
	protected transient TaskThread[] threads;
	protected transient Task[] tasks;
	
	protected int findTask(Task task) {
		for (int k = 0; k < amount;  k++) {
			if (tasks[k]==task)
				return k;
		}
		return -1;
	}
	
	protected TaskThread findThread(Task task) {
		for (int k = 0; k < amount;  k++) {
			if (tasks[k]==task)
				return threads[k];
		}
		return null;
	}
	
	private transient boolean full = false;
	protected int amount; 
	
	private boolean running = true;
	boolean isRunning() {
		return running;
	}
	
	
	class TaskThread extends Thread {
		int number;
		AbstractThreadTaskRunner attr;
		transient boolean paused;
		public TaskThread(int number, AbstractThreadTaskRunner attr) {
			this.number = number;
			this.attr = attr;
		}
		
		public synchronized void pause() {
			paused = true;
			this.notifyAll();
		}
		
		public synchronized void unpause() {
			paused = false;
			this.notifyAll();
		}
		
		public boolean isPaused() {
			return paused;
		}
			
		public void run() {
			while (isRunning()) {
				paused = true;
				synchronized(threads[number]) {
					this.notifyAll();
					while ((tasks[number] == null || tasks[number] == RESERVED || paused) && isRunning())
						try {
							this.wait();
						} catch (InterruptedException e) {
						}
					
				}
				if (isRunning())
					runThread(this, number, tasks[number]);
			}
		}
		
	}

	public AbstractThreadTaskRunner(int amount) {
		this.amount = amount;
		tasks = new Task[amount];
		threads	= new TaskThread[amount];
		
		for (int k=0; k < amount; k++) {
			threads[k] = new TaskThread(k, this);
			threads[k].start();
		}
	}
	
	public abstract void runThread(TaskThread taskthread, int number, Task task);
	
	public boolean isPaused(Task task) {
		TaskThread tthread = findThread(task);
		return (tthread == null) ? false : findThread(task).isPaused(); 
			
	}

	public void assign(Task task, int id) {
		synchronized(threads[id]) {
			tasks[id] = task;
			threads[id].notifyAll();
		}
	}

	public Task[] getTasks() {
		return tasks;
	}

	public int reserveTask() {
		if (full)
			return -1;
		int ret = -1;
		synchronized (this) {
			for (int k=0; k<amount; k++) {
				if (tasks[k] == null) {
					tasks[k] = RESERVED;
					ret=k;
				}
			}
			if (ret==-1)
				full = true;
		}
		return ret;
	}

	public void cancelReserveTask(int id) {
		tasks[id]=null;
		full = false;
	}

	public void removeTask(Task task) {
		tasks[findTask(task)] = null;
		full = false;
	}

	protected boolean runTask(Task task) {
		if ( super.runTask(task)) {
			full = false;
			return true;
		}
		return false;
	}

}
